//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_review_dao

import (
	"context"
	"regexp"

	"atomgit.com/openlinksaas-org/api-server/dao/db_ns"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_review_api"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type ReviewInfoDbItem struct {
	ReviewId         string   `bson:"_id"`
	ProjectId        string   `bson:"projectId"`
	Title            string   `bson:"title"`
	ReviewType       uint32   `bson:"reviewType"`
	Desc             string   `bson:"desc"`
	MemberUserIdList []string `bson:"memberUserIdList"`
	CreateTime       int64    `bson:"createTime"`
	UpdateTime       int64    `bson:"updateTime"`
}

func (item *ReviewInfoDbItem) ToReviewInfo() *project_review_api.ReviewInfo {
	return &project_review_api.ReviewInfo{
		ReviewId:   item.ReviewId,
		Title:      item.Title,
		ReviewType: project_review_api.REVIEW_TYPE(item.ReviewType),
		MemberList: []*project_review_api.ReviewMemberItem{},
		ResultList: []*project_review_api.ReviewResultItem{},
		LinkList:   []*project_review_api.ReviewLinkItem{},
		Desc:       item.Desc,
		CreateTime: item.CreateTime,
		UpdateTime: item.UpdateTime,
	}
}

type _ReviewDao struct {
	mc *mongo.Collection
}

func newReviewDao(db *mongo.Database) (*_ReviewDao, error) {
	mc := db.Collection(db_ns.DB_NS_PROJECT_REVIEW + "review")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"projectId", 1}, {"createTime", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_ReviewDao{mc: mc}, nil
}

func (db *_ReviewDao) Insert(ctx context.Context, dbItem *ReviewInfoDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_ReviewDao) Exist(ctx context.Context, projectId, reviewId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"_id": reviewId, "projectId": projectId})
	return count > 0, err
}

func (db *_ReviewDao) Get(ctx context.Context, projectId, reviewId string) (*ReviewInfoDbItem, error) {
	retItem := &ReviewInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"_id": reviewId, "projectId": projectId}).Decode(retItem)
	return retItem, err
}

func (db *_ReviewDao) Remove(ctx context.Context, projectId, reviewId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"_id": reviewId, "projectId": projectId})
	return err
}

func (db *_ReviewDao) Update(ctx context.Context, projectId, reviewId, title string,
	reviewType project_review_api.REVIEW_TYPE, desc string, memberUserIdList []string, nowTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"_id": reviewId, "projectId": projectId},
		bson.M{"$set": bson.M{
			"title":            title,
			"reviewType":       uint32(reviewType),
			"desc":             desc,
			"memberUserIdList": memberUserIdList,
			"updateTime":       nowTime,
		}})
	return err
}

func (db *_ReviewDao) Count(ctx context.Context, projectId string) (uint32, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"projectId": projectId})
	return uint32(count), err
}

func (db *_ReviewDao) List(ctx context.Context, projectId string, offset, limit int64) ([]*ReviewInfoDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{"projectId": projectId}, options.Find().SetSkip(offset).SetLimit(limit).SetSort(bson.M{"createTime": -1}))
	if err != nil {
		return nil, err
	}
	retList := []*ReviewInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_ReviewDao) CountSimple(ctx context.Context, projectId string,
	filterByReviewType bool, reviewType project_review_api.REVIEW_TYPE, filterByTitleKeyword bool, titleKeyword string) (uint32, error) {
	query := bson.M{"projectId": projectId}
	if filterByReviewType {
		query["reviewType"] = uint32(reviewType)
	}
	if filterByTitleKeyword {
		query["title"] = primitive.Regex{
			Pattern: regexp.QuoteMeta(titleKeyword),
			Options: "i",
		}
	}

	count, err := db.mc.CountDocuments(ctx, query)
	return uint32(count), err
}

func (db *_ReviewDao) ListSimple(ctx context.Context, projectId string,
	filterByReviewType bool, reviewType project_review_api.REVIEW_TYPE, filterByTitleKeyword bool, titleKeyword string,
	offset, limit int64) ([]*ReviewInfoDbItem, error) {
	query := bson.M{"projectId": projectId}
	if filterByReviewType {
		query["reviewType"] = uint32(reviewType)
	}
	if filterByTitleKeyword {
		query["title"] = primitive.Regex{
			Pattern: regexp.QuoteMeta(titleKeyword),
			Options: "i",
		}
	}

	cursor, err := db.mc.Find(ctx, query, options.Find().SetSkip(offset).SetLimit(limit).SetSort(bson.M{"createTime": -1}))
	if err != nil {
		return nil, err
	}
	retList := []*ReviewInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}
